package com.hp.bon.sgw.core;

import static com.hp.bon.sgw.Constants.LOG;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import com.hp.bon.sgw.Constants.NodeStatus;
import com.hp.bon.sgw.convert.Xml2AVPConvetor;
import com.hp.bon.sgw.core.channel.IChannel;
import com.hp.bon.sgw.core.route.RouteHopInfo;
import com.hp.bon.sgw.core.route.RouteInfo;
import com.hp.bon.sgw.domain.Node;
import com.hp.bon.sgw.domain.SGWCapabilityProvided;
import com.hp.bon.sgw.domain.SGWChannel;
import com.hp.bon.sgw.service.ConfigService;
import com.hp.bon.sgw.start.SpringContext;

/**
 * @author wanghan
 * 
 */
public class ChannelServer {
	static public ConcurrentHashMap<String, RouteInfo> routeMap = new ConcurrentHashMap<String, RouteInfo>();
	static public ConcurrentHashMap<Integer, IChannel> channelMap = new ConcurrentHashMap<Integer, IChannel>();

	private static ChannelServer instance;

	public static ChannelServer getInstance() {
		if (instance == null) {
			instance = new ChannelServer();
		}
		return instance;
	}

	public void start() {

		ConfigService confSrv = SpringContext.getInstance().getConfigService();
		Xml2AVPConvetor.getInstance();
		BuzProcessorManager.getInstance();

		updateRouteConfig(confSrv);

	}

	public void stop() {
		stopChannels();
	}

	private void stopChannels() {
		for (Entry<Integer, IChannel> entry : ChannelServer.channelMap.entrySet()) {
			entry.getValue().stop();
		}
	}

	public static RouteInfo findRoute(String scid) {
		RouteInfo route = (RouteInfo) routeMap.get(scid);
		if (route == null) {
			try {
				String capaName = scid.substring(0, scid.indexOf('@'));
				route = routeMap.get(capaName);
			} catch (Exception e) {
				//
			}
		}
		if (route == null)
			return null;
		route.calcNextHop();
		return route;
	}

	static public void updateRouteConfig(ConfigService confSrv) {

		// 支持在线新增channel，如果channel没有启动，也支持变更channel参数
		for (SGWChannel sgwChannel : ConfigService.sgwChannelMap.values()) {
			IChannel channel = ChannelServer.channelMap.get(sgwChannel.getId());
			if (channel != null)
				continue;			
			try {
				String className = sgwChannel.getChannelType();
//				//兼容老的配置
//				if(!className.contains("."))
//				{
//					className = "com.hp.bon.sgw.core.channel."+className;
//				}
				Class<?> cls = Class.forName(className);
				Class[] paramDef = new Class[] { SGWChannel.class};
				Constructor<?> constructor = cls.getConstructor(paramDef);
				
				// create a new instance by using the constructor
				Object[] params = new Object[] {sgwChannel};
				channel = (IChannel) constructor.newInstance(params);
				ChannelServer.channelMap.put(sgwChannel.getId(), channel);
				LOG.info("create channel succeed:" + sgwChannel.getChannelType() + ",channelHost:" + sgwChannel.getChannelHost());
			} catch (Exception e) {
				e.printStackTrace();
				LOG.warn("create channel failed:" + sgwChannel.getChannelType() + ",channelHost:" + sgwChannel.getChannelHost()+",exection:"+e.getMessage());
				System.exit(-1);
			}
//			// 创建新的channel
//			if (DCCChannel.class.getSimpleName().equals(sgwChannel.getChannelType())) {
//				NodeSettings settings = DCCChannel.buildDCCNodeParams(sgwChannel, confSrv);
//				if (settings != null) {
//					channel = new DCCChannel(settings, sgwChannel, confSrv);
//					ChannelServer.channelMap.put(sgwChannel.getId(), channel);
//				}
//			} else if (DrproxyChannel.class.getSimpleName().equals(sgwChannel.getChannelType())) {
//				NodeSettings settings = DCCChannel.buildDCCNodeParams(sgwChannel, confSrv);
//				if (settings != null) {
//					channel = new DrproxyChannel(settings, sgwChannel, confSrv);
//					ChannelServer.channelMap.put(sgwChannel.getId(), channel);
//				}
//			} else if (SoapChannel.class.getSimpleName().equals(sgwChannel.getChannelType())) {
//				channel = new SoapChannel(sgwChannel);
//				ChannelServer.channelMap.put(sgwChannel.getId(), channel);
//			} else if (NPChannel.class.getSimpleName().equals(sgwChannel.getChannelType())) {
//				channel = new NPChannel(sgwChannel);
//				ChannelServer.channelMap.put(sgwChannel.getId(), channel);
//			} else if (NAVSoapChannel.class.getSimpleName().equals(sgwChannel.getChannelType())) {
//				channel = new NAVSoapChannel(sgwChannel);
//				ChannelServer.channelMap.put(sgwChannel.getId(), channel);
//			} else {
//				LOG.warn("unknown channel type:" + sgwChannel.getChannelType() + ",channelHost:" + sgwChannel.getChannelHost());
//			}
		}

		// 关联Node与Channel实体,可以在线更改channel
		for (Node node : ConfigService.id2NodeMap.values()) {
			IChannel channel = ChannelServer.channelMap.get(node.getChannelId());
			if (channel == null) {
				LOG.warn("Node not belong to any channel,nodeId=" + node.getId() + ",host=" + node.getHostId() + ",channelId=" + node.getChannelId());
				continue;
			}
			node.channel = channel;
			// 如果node需要SGW主动连接，需要增加的Persist中
			// if (node.getConnectType() == 1) {
			// channel.addPersist(node);
			// }
		}

		// 如果T_CAPABILITY_PROVIDED发生变更，重新构造routeMap
		for (SGWCapabilityProvided cp : ConfigService.capabilityProvidedList) {
			String scid = cp.getServiceContextID();
			Node node = ConfigService.id2NodeMap.get(cp.getPeerNodeId());
			if (node == null) {
				LOG.warn("node == null,cp.getPeerNodeId():" + cp.getPeerNodeId());
				continue;
			}
			RouteInfo route = ChannelServer.routeMap.get(scid);
			if (route == null) {
				route = new RouteInfo(scid);
				ChannelServer.routeMap.put(scid, route);
			}
			RouteHopInfo hopInfo = route.findRouteHopInfo(node);
			if (hopInfo == null) {
				hopInfo = new RouteHopInfo(node, cp.getPriority(), cp.getWeight());
				route.addRouteHopInfo(hopInfo);
			} else {
				hopInfo.priority = cp.getPriority();
				hopInfo.weight = cp.getWeight();
			}
		}
		for (RouteInfo route : ChannelServer.routeMap.values()) {
			String scid = route.scid;
			ArrayList<RouteHopInfo> deletehopList = new ArrayList<RouteHopInfo>();
			for (RouteHopInfo routeHopInfo : route.hopList) {
				int nodeid = routeHopInfo.node.getId();
				boolean isFound = false;
				for (SGWCapabilityProvided cp : ConfigService.capabilityProvidedList) {
					if (cp.getServiceContextID().equals(scid) && cp.getPeerNodeId() == nodeid) {
						isFound = true;
						break;
					}
				}
				if (!isFound)
					deletehopList.add(routeHopInfo);
			}
			// 如果删除的个数与内存保存个数相同，则删除整个route
			// 如果个数不同，则替换整个list（从线程安全角度考虑）
			if (deletehopList.size() == route.hopList.size()) {
				ChannelServer.routeMap.remove(scid);
			} else if (deletehopList.size() != 0) {
				route.deleteHops(deletehopList);
			}
		}
		for (RouteInfo route : ChannelServer.routeMap.values()) {
			route.checkRoute();
		}

		// 启动或停止channel
		for (IChannel channel : ChannelServer.channelMap.values()) {
			SGWChannel sgwChannel = channel.getSGWChannel();
			if (sgwChannel.getIsStart() == 1) {
				if (sgwChannel.getStatus() != NodeStatus.ON_LINE) {
					try {
						channel.start();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			} else if (sgwChannel.getStatus() == NodeStatus.ON_LINE) {
				channel.stop();
			}
		}
	}
}
